#ifndef GAME_RENDERER_H
#define GAME_RENDERER_H

#include "Utils.h"

#include <map>

#include <glm/glm.hpp>
#include <GL/glew.h>

namespace VectorTD
{
	class GameRenderer
	{
	public:

		enum Texture
		{
			TEXTURE_STAR,
		};

		enum Shader
		{
			SHADER_DEBUG,
			SHADER_SIMPLE_TRANSFORM,
			SHADER_SIMPLE_TRANSFORM_COLOR,
			// SHADER_PARTICULE,
		};

		struct GameMesh
		{
			GLuint vertexbuffer;
			GLenum mode;
			GLsizei count;
			Shader shader;
		};

		struct ShaderParams
		{
			glm::mat4* model;
			glm::vec4* meshColor;
		};

		struct MeshPoint
		{
			GLfloat x,y,z;	// Position

			MeshPoint(GLfloat p_x, GLfloat p_y, GLfloat p_z){x = p_x; y = p_y; z = p_z;};
			MeshPoint(){x = 0.0f; y = 0.0f; z = 0.0f;};
		};

		static GameRenderer& GetInstance();
		GameMesh* CreateMesh(std::vector<MeshPoint>& p_points, Shader p_shader, bool p_isLooping, float p_lineSize = 0.02f);

		void AddMeshToRender(GameMesh* p_mesh, ShaderParams shaderParam);

		ShaderParams AddParticuleToRender(Texture p_texture);

		void Render(double p_deltaMs);
	private:

		struct ShaderInfos
		{
			GLuint programId;
			GLuint mvpHandle;
			GLuint meshColorHandle;
		};

		// A map containing all the program shader loaded
		std::map<const char*, GLuint> m_vertexShader;
		std::map<const char*, GLuint> m_fragmentShader;
		std::map<std::pair<GLuint, GLuint>, GLuint> m_programIds;

		// Vector containing the ShaderInfos indexed by the value of enum Shader.
		// ie: m_shaderInfos[SHADER_DEBUG] contain the information of the shader: SHADER_DEBUG
		std::vector<ShaderInfos> m_shaderInfos;

		// A vector of vector of mesh to render.
		// First dimension is indexed by Shader, for exemple: m_meshesToRender[SHADER_SIMPLE_TRANSFORM] contain all the mesh to be drawn with shader SHADER_SIMPLE_TRANSFORM.
		// Second dimension contain a pair of mesh and shader params to render that mesh
		std::vector<std::vector<std::pair<GameMesh*, ShaderParams> > > m_meshesToRender;
		
		// Nearly the same as m_meshesToRender except that for particules we have only one shader but multiple texture, and only one mexh (a square)
		// First dimension is indexed by Texture, for exemple: m_meshesToRender[TEXTURE_STAR] contain all the mesh to be drawn with texture TEXTURE_STAR.
		// Second dimension contain a pair of mesh and shader params to render that mesh
		std::vector<std::vector<ShaderParams> > m_particulesToRender;
		std::vector<glm::mat4> m_particulesModelMat;

		// Global matrice for the camera
		glm::mat4 m_projMat;
		glm::mat4 m_viewMat;
		
		void LoadShaders();
		GameRenderer();
		~GameRenderer();
	};
}

#endif